package com.sghd.football.module.data.dao;

import org.hibernate.HibernateException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 数据库操作模板
 */
@Component
@SuppressWarnings("unchecked")
public class MysqlTemplate {
	private Logger logger = LoggerFactory.getLogger(MysqlTemplate.class);

	@Autowired
	private SessionFactory sessionFactory;

	public void save(final Object object) {
		execute(new SessionCallback<Integer>() {
			@Override
			public Integer doInSession(Session session) throws HibernateException, SQLException {
				session.saveOrUpdate(object);
				return 1;
			}
		});
	}

	public Boolean insert(final Object obj) {
		return execute(new SessionCallback<Boolean>() {
			@Override
			public Boolean doInSession(Session session) throws HibernateException, SQLException {
				session.save(obj);
				return true;
			}
		});
	}

	public <T> T findById(final Serializable id, final Class<T> clazz) {
		return execute(new SessionCallback<T>() {
			@Override
			public T doInSession(Session session) throws HibernateException, SQLException {
				return (T)session.get(clazz, id);
			}
		});
	}

	public <T> T findOne(final DetachedCriteria criteria) {
		return execute(new SessionCallback<T>() {
			@Override
			public T doInSession(Session session) throws HibernateException, SQLException {
				List<Object> lists = criteria.getExecutableCriteria(session).list();
				if (null != lists && lists.size() > 0) {
					return (T) lists.get(0);
				}
				return null;
			}
		});
	}

	/** 删除 */
	public void remove(final DetachedCriteria criteria) {
		execute(new SessionCallback<Integer>() {
			@Override
			public Integer doInSession(Session session) throws HibernateException, SQLException {
				List<Object> list = criteria.getExecutableCriteria(session).list();
				for (Object object : list) {
					session.delete(object);
				}
				return list.size();
			}
		});
	}

	public <T> List<T> find(final DetachedCriteria criteria) {
		return execute(new SessionCallback<List<T>>() {
			@Override
			public List<T> doInSession(Session prev) throws HibernateException, SQLException {
				List<T> lists = criteria.getExecutableCriteria(prev).list();
				return lists;
			}
		});
	}
	public <T> List<T> findAll(final Class<T> clazz) {
		return execute(new SessionCallback<List<T>>() {
			@Override
			public List<T> doInSession(Session prev) throws HibernateException, SQLException {
				DetachedCriteria deprecated = DetachedCriteria.forClass(clazz);
				List<T> lists = deprecated.getExecutableCriteria(prev).list();
				return lists;
			}
		});
	}

	/**表集合*/
	public Collection<String> getTables() {
		return execute(new SessionCallback<List<String>>() {
			@Override
			public List<String> doInSession(Session session) throws HibernateException, SQLException {
				SQLQuery query = session.createSQLQuery("show tables");
				List<String> results = query.list();
				if(results != null){
					List<String> temp = new ArrayList<>();
					for (String table : results) {
						temp.add(table.toLowerCase());
					}
					return temp;
				}
				return new ArrayList<>();
			}
		});
	}
	
	private <T> T execute(SessionCallback<T> callback){
		Session session = sessionFactory.openSession();
		T result = null;
		try {
			result = callback.doInSession(session);
			session.flush();
		} catch (HibernateException | SQLException e) {
			logger.error("MysqlException", e);
		} finally{
			session.close();
		}
		return result;
	}
	
}

interface SessionCallback<T>{
	T doInSession(Session session) throws HibernateException, SQLException;
}

